#include <linux/module.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>

unsigned int major;
static struct class *linus_class;
static int g_key;

static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);

static irqreturn_t linus_irq(int irqid, void *v)
{
	printk("---> %d\n", irqid);
	g_key = 1;
	wake_up_interruptible(&gpio_key_wait);
	return IRQ_HANDLED;
}

static int chrdev_open(struct inode *inode, struct file *file)
{

	return 0;
}

static ssize_t chrdev_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
{
	wait_event_interruptible(gpio_key_wait, g_key);

	copy_to_user(user_buf, &g_key, 4);

	g_key = 0;

	return 4;
}

static const struct file_operations ops = {
	.owner = THIS_MODULE,
//	.open = chrdev_open,
	.read = chrdev_read,
	
};

static int gpio_probe(struct platform_device *pdev)
{
	struct device_node *child = NULL;

	for_each_child_of_node(pdev->dev.of_node, child)
	{
		int count = of_gpio_named_count(child, "gpi-gpios");
		int num = 0;
			
		for(; num<count; num++)
		{
			unsigned int gpio = of_get_named_gpio(child, "gpi-gpios", num);
			printk("gpio = %d\n", gpio);
			struct gpio_desc *d = gpio_to_desc(gpio);

			unsigned irq = gpiod_to_irq(d);
			request_irq(irq, linus_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "linus", NULL);			
		}
	}

/*start: 在/dev/下创建设备节点*/
	major = register_chrdev(0, "linus", &ops);
	linus_class = class_create(THIS_MODULE, "linus_class");

	if (IS_ERR(linus_class))
	{
		unregister_chrdev(major, "linus");
		return -1;
	}

	device_create(linus_class, NULL, MKDEV(major, 0), NULL, "linus");
/*end:*/	
	return 0;
}


static struct of_device_id gpio_keys_of_match[] = {
	{ .compatible = "linus,gpio", },
	{ },
};

static struct platform_driver gpio_keys_device_driver = {
	.probe		= gpio_probe,
	.driver		= {
		.name	= "linus",
		.owner	= THIS_MODULE,
//		.pm	= &gpio_keys_pm_ops,
		.of_match_table = of_match_ptr(gpio_keys_of_match),
	}
};

static int __init linus_wkup_init(void)
{
	return platform_driver_register(&gpio_keys_device_driver);
}

static void __exit linus_wkup_exit(void)
{
	platform_driver_unregister(&gpio_keys_device_driver);
	unregister_chrdev(major, "linus");
}

late_initcall(linus_wkup_init);
module_exit(linus_wkup_exit);

MODULE_LICENSE("GPL");




